/**
 * 
 */
package adnotatio.rdf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * @author kotelnikov
 */
public class Container extends PropertyValue {

    /**
     * 
     */
    private static final long serialVersionUID = -5499308131197348449L;

    private ID fID;

    private List fList = new ArrayList();

    protected Container(Model model, ID id) {
        super(model);
        fID = id;
    }

    /**
     * @see adnotatio.rdf.Resource#accept(adnotatio.rdf.IValueVisitor)
     */
    public void accept(IValueVisitor visitor) {
        visitor.visit(this);
    }

    /**
     * @param pos
     * @param object
     */
    public void add(int pos, Object object) {
        checkPosition(pos, false);
        PropertyValue propertyValue = toPropertyValue(object);
        fList.add(pos, propertyValue);
    }

    /**
     * Adds a new value at the end of the collection
     * 
     * @param value the value to add
     */
    public void add(Object value) {
        PropertyValue propertyValue = toPropertyValue(value);
        fList.add(propertyValue);
    }

    /**
     * @param values
     */
    public void addAllValues(Collection values) {
        for (Iterator iterator = values.iterator(); iterator.hasNext();) {
            Object object = iterator.next();
            PropertyValue propertyValue = toPropertyValue(object);
            fList.add(propertyValue);
        }
    }

    /**
     * @param values
     */
    public void addAllValues(Container values) {
        for (Iterator iterator = values.getIterator(); iterator.hasNext();) {
            Object object = iterator.next();
            PropertyValue propertyValue = toPropertyValue(object);
            fList.add(propertyValue);
        }
    }

    /**
     * @param object
     */
    public void addValue(Object object) {
        PropertyValue propertyValue = toPropertyValue(object);
        fList.add(propertyValue);
    }

    /**
     * @param propertyValue
     */
    public void addValue(PropertyValue propertyValue) {
        fList.add(propertyValue);
    }

    /**
     * Checks that the specified position is less than the size of the internal
     * list
     * 
     * @param pos the position to check
     * @param read if this flag is <code>true</code> then this method checks
     *        that the position is not equals to the size of the list (that it
     *        is possible to read values from the specified position)
     */
    private void checkPosition(int pos, boolean read) {
        int size = fList.size();
        if (pos < 0 || pos > size || (read && pos == size))
            throw new IndexOutOfBoundsException();
    }

    /**
     * @return the first value in this collection
     */
    public PropertyValue getFirstValue() {
        return (PropertyValue) (!fList.isEmpty() ? fList.get(0) : null);
    }

    /**
     * @return the ID
     */
    public ID getID() {
        return fID;
    }

    /**
     * Returns an iterator over all values contained in this bag. Each returned
     * value is an instance of the {@link PropertyValue} class.
     * 
     * @return an iterator over all values contained in this bag
     */
    public Iterator getIterator() {
        return fList.iterator();
    }

    /**
     * @return the size of this bag
     */
    public int getSize() {
        return fList.size();
    }

    /**
     * @see adnotatio.rdf.Entity#getStringValue()
     */
    protected String getStringValue() {
        return fID.getURL();
    }

    /**
     * This method returns the first value from this container (if any)
     * 
     * @see adnotatio.rdf.PropertyValue#getValue()
     */
    public Object getValue() {
        PropertyValue value = getFirstValue();
        Object result = null;
        if (value != null) {
            result = value.getValue();
        }
        return result;
    }

    /**
     * Returns the value from the specified position
     * 
     * @param pos the position of the value to return
     * @return the value from the specified position
     */
    public PropertyValue getValue(int pos) {
        checkPosition(pos, true);
        return (PropertyValue) fList.get(pos);
    }

    /**
     * Removes a value from the specified position and returns it
     * 
     * @param pos the position from which the value should be removed
     * @return the removed value
     */
    public PropertyValue removeValue(int pos) {
        checkPosition(pos, true);
        PropertyValue value = (PropertyValue) fList.remove(pos);
        return value;
    }

    /**
     * Sets the given value in the specified position
     * 
     * @param pos the position where the value should be stored
     * @param object the object to set
     */
    public void setValue(int pos, Object object) {
        checkPosition(pos, true);
        PropertyValue propertyValue = toPropertyValue(object);
        fList.set(pos, propertyValue);
    }

    /**
     * Adds the specified values to this collection
     * 
     * @param values a list of values to add
     */
    public void setValues(Container values) {
        fList.clear();
        addAllValues(values);
    }

    /**
     * Adds the specified values to this collection
     * 
     * @param values a list of values to add
     */
    public void setValues(List values) {
        fList.clear();
        addAllValues(values);
    }

}
